package org.bukkit.pm;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.bukkit.Server;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginLoader;
import org.bukkit.plugin.java.JavaPlugin;

public abstract class GenericPlugin extends JavaPlugin {
	
	private final static Logger LOGGER = Logger.getLogger("Minecraft");
	
	protected final Properties _properties = new Properties();
	private boolean _modified = false; //if properties were modified

	private String _version, _name, _propfile;
	
	public GenericPlugin(PluginLoader pluginLoader, Server instance,
			PluginDescriptionFile desc, File folder, File plugin,
			ClassLoader cLoader) {
		super(pluginLoader, instance, desc, folder, plugin, cLoader);
        //Runtime.getRuntime().addShutdownHook(new GenericPluginShutdownHook(this));
	}
	
    public final void log(Level level, String message){
    	LOGGER.log(level,"["+_name+"] "+message);
    }

	public void close() {
		if(_modified) storeProperties();
	}

	public void init() {
        PluginDescriptionFile pdfFile = this.getDescription();
        _version = pdfFile.getVersion();
        _name = pdfFile.getName();
        _propfile = _name+".cfg";
        log(Level.INFO, _version);
        
        _modified=false; 
        loadProperties();
	}
	
	public final String getVersion(){
		return _version;
	}
	
	public final String getName(){
		return _name;
	}
	
	public final void setModified(boolean modified){
		_modified=modified;
	}
	
	public final boolean isModified(){
		return _modified;
	}

	public final boolean setProperty(String key, boolean val){
		return setProperty(key, Boolean.toString(val));
    }
    
    public final boolean setProperty(String key, long val){
    	return setProperty(key, Long.toString(val));
    }
    
    public final boolean setProperty(String key, int val){
    	return setProperty(key, Integer.toString(val));
    }
    
    public final boolean setProperty(String key, String val){
    	String old = _properties.getProperty(key);
    	if(old==null || !old.equals(val)){
	    	_properties.setProperty(key, val);
	    	_modified=true;
	    	return true;
    	}else{
    		return false;
    	}
    }
    
    public final long getProperty(String key, long def){
    	String s = _properties.getProperty(key);
    	if(s==null){
    		_properties.setProperty(key, Long.toString(def));
    		_modified=true;
    		return def;
    	}else{
    		long v = def;
    		try{
    			v = Long.parseLong(s);
    		}catch(NumberFormatException e){
    			log(Level.WARNING,"bad number "+s);
    			_properties.setProperty(key, Long.toString(def));
    			_modified=true;
    		}
    		return v;
    	}
    }
    
    public final boolean getProperty(String key, boolean def){
    	String s = _properties.getProperty(key);
    	if(s==null){
    		_properties.setProperty(key, Boolean.toString(def));
    		_modified=true;
    		return def;
    	}else{
    		return Boolean.parseBoolean(s);
    	}
    }
    
    public final int getProperty(String key, int def){
    	String s = _properties.getProperty(key);
    	if(s==null){
    		_properties.setProperty(key, Integer.toString(def));
    		_modified=true;
    		return def;
    	}else{
    		int v = def;
    		try{
    			v = Integer.parseInt(s);
    		}catch(NumberFormatException e){
    			log(Level.WARNING,"bad number "+s);
    			_properties.setProperty(key, Integer.toString(def));
    			_modified=true;
    		}
    		return v;
    	}
    }
    
    public final boolean hasProperty(String key){
    	return _properties.getProperty(key)!=null;
    }
    
    public final String getProperty(String key, String def){
    	String s = _properties.getProperty(key);
    	if(s==null){
    		_properties.setProperty(key, def);
    		_modified=true;
    		return def;
    	}else{
    		return s;
    	}
    }
    
    private final void loadProperties(){
    	//load from file
    	try {
    		FileInputStream f = new FileInputStream(_propfile);
			_properties.load(f);
			f.close();
			_modified=false;
		} catch (FileNotFoundException e) {
			storeProperties(); //create file with standard values and jump out
		} catch (IOException e) {
			log(Level.SEVERE,"IO error while loading configuration: using defaults");
			e.printStackTrace();
			return;
		}
    }
    
    public final void storeProperties(){
    	try {
    		FileOutputStream f = new FileOutputStream(_propfile);
			_properties.store(f, _name+" "+_version+" Properties File");
			f.close();
			_modified=false;
			log(Level.INFO,"configuration stored to "+_propfile);
		} catch (Exception e) {
			log(Level.SEVERE,"unable to store configuration");
			e.printStackTrace();
		}
    }

}
